﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Xml.Linq;

namespace Hosting
{
    public class WcfServer
    {
        private ServiceHost host = null;
        private volatile static WcfServer _instance = null;
        private static readonly object lockHelper = new object();
        private const string ContractsName = "Contracts.xml";
        private readonly string AssPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Contracts.dll");

        private WcfServer()
        {
        }

        public static WcfServer CreateInstance()
        {
            if (_instance == null)
            {
                lock (lockHelper)
                {
                    if (_instance == null)
                        _instance = new WcfServer();
                }
            }
            return _instance;
        }

        public void Open(string HostIP)
        {
            try
            {
                HostOpen(HostIP);
            }
            catch (Exception ex)
            {
            }
        }

        public void Close()
        {
            if (host != null)
                host.Close();
        }

        /// <summary>
        /// 局域网
        /// </summary>
        private void HostOpen(string HostIP)
        {
            #region 局域网

            try
            {
                Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/calculatorservice", string.IsNullOrEmpty(HostIP) ? "127.0.0.1" : HostIP, 9999));

                #endregion 局域网

                if (host == null)
                    host = new ServiceHost(typeof(Services.ServiceImp), baseAddress);
                // 设置证书
                host.Credentials.ServiceCertificate.SetCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);
                NetTcpBinding bind = new NetTcpBinding();
                bind.Security.Mode = SecurityMode.Message;
                bind.MaxReceivedMessageSize = 2147483647;

                if (host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null)
                {
                    BindingElement metaElement = new TcpTransportBindingElement();
                    CustomBinding metaBind = new CustomBinding(metaElement);
                    host.Description.Behaviors.Add(new System.ServiceModel.Description.ServiceMetadataBehavior());
                }
                var sourceAssembly = System.Reflection.Assembly.GetExecutingAssembly();
                var resourceNames = sourceAssembly.GetManifestResourceNames();
                string currDBVersionPath = string.Format("{0}.{1}", sourceAssembly.GetName().Name, ContractsName);

                var stream = sourceAssembly.GetManifestResourceStream(currDBVersionPath);
                XElement root = XElement.Load(stream);
                if (root != null)
                {
                    IDictionary<string, string> objectDefine = new Dictionary<string, string>();

                    var objects = from obj in root.Descendants()
                                  where obj.Attribute("isactive").Value == "1"
                                  select obj;
                    objectDefine = objects.ToDictionary(
                            k => k.Attribute("address").Value,
                            v =>
                            {
                                return v.Attribute("namespace").Value;
                            }
                        );
                    foreach (var item in objectDefine)
                    {
                        System.Reflection.Assembly AsbmContract = System.Reflection.Assembly.Load("Contracts");
                        if (AsbmContract == null)
                        {
                            throw new ArgumentException("获取Contracts.dll程序集信息为空.");
                        }
                        if (string.IsNullOrEmpty(item.Value))
                        {
                            continue;
                        }
                        Type supType = AsbmContract.GetType(item.Value, false, true);
                        if (supType == null)
                        {
                            continue;
                        }
                        string address = item.Key;
                        host.AddServiceEndpoint(supType, bind, "");
                        host.AddServiceEndpoint(supType, bind, address);
                    }
                }

                if (host.State != CommunicationState.Opened)
                {
                    host.Opened += delegate
                    {
                        Console.WriteLine("WCF服务已启动,地址:{0}", string.Format("Address:{0}", baseAddress.AbsoluteUri));
                    };
                    host.Open();
                    while (true)
                    {
                        Services.ChannelManager.Instance.NotifyMessage(string.Format("服务器时间:{0}", DateTime.Now));
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}